package redecolaborativa.objetos;

import java.io.Serializable;
import java.util.Calendar;
import java.util.GregorianCalendar;
import redecolaborativa.excecoes.*;
import redecolaborativa.sistema.Gerenciador;
import redecolaborativa.sistema.Usuario;

/**
 * Classe que representa um emprestimo realizado pelo usuario.
 * @author Isabelly Rocha, Lilia Sampaio e Pedro Adelino.
 */
public class Emprestimo implements Serializable {
	private static final long serialVersionUID = 1L;
	private static int RETORNA_ID = 1; 
	private Usuario beneficiado;
	private Item item;
	private GregorianCalendar dataInicial, dataFinal;
	private boolean canceladoAntes, terminado;
	private int tempoPrevisto, idEmprestimo, idRequisicao;
	
	/**
	 * Cria um objeto do tipo emprestimo.
	 * @param Beneficiado Usuario que vai receber o item
	 * @param Item Item que vai ser emprestado
	 * @param TempoPrevisto Tempo que o usuario vai passar com o item
	 * @throws BeneficiadoInvalidoException Se o usuario beneficiado for nulo
	 * @throws ItemInvalidoException Se o item empretado for nulo
	 * @throws NumeroNegativoException Se o tempo for negativo
	 */
	public Emprestimo(Usuario beneficiado, Item item, int tempoPrevisto) throws BeneficiadoInvalidoException, ItemInvalidoException, NumeroNegativoException {
		if(beneficiado == null) {
			throw new BeneficiadoInvalidoException("O beneficiado nao pode ser nulo.");
		} if(item == null) {
			throw new ItemInvalidoException("O item desejado nao pode ser nulo.");
		} if(tempoPrevisto <= 0) {
			throw new NumeroNegativoException("Duracao inválida");
		}
		this.beneficiado = beneficiado;
		this.item = item;
		this.tempoPrevisto = tempoPrevisto;
	}
	
	/**
	 * Reseta o gerador do id
	 */
	public static void resetaGeradorID() {
		RETORNA_ID = 1;
	}
	
	/**
	 * Recupera o usuario beneficiado.
	 * @return O Usuario beneficiado
	 */
	public Usuario getBeneficiado() {
		return beneficiado;
	}
	
	/**
	 * Recupera o item emprestado.
	 * @return O item emprestado
	 */
	public Item getItem() {
		return item;
	}
	
	/**
	 * Recupera o tempo previsto do emprestimo.
	 * @return O tempo presvisto
	 */
	public int getTempoPrevisto() {
		return tempoPrevisto;
	}
	
	/**
	 * Recupera a data inicial do emprestimo.
	 * @return Data inicial do emprestimo.
	 */
	public GregorianCalendar getDataInicial() {
		return dataInicial;
	}
	
	/**
	 * Recupera a data final do emprestimo.
	 * @return Data final do emprestimo.
	 */
	public GregorianCalendar getDataFinal() {
		return dataFinal;
	}
	
	/**
	 * Verifica se o emprestimo foi cancelado antes do tempo previsto.
	 * @return True Caso foi cancelado antes do tempo previsto e false em caso contrario
	 */
	public boolean canceladoAntes() {
		return canceladoAntes;
	}
	
	/**
	 * Modifica o status de cancelamento do emprestimo.
	 * @param cancelado Novo status de cancelamento do item.
	 */
	public void setCancelado(boolean cancelado) {
		this.canceladoAntes = cancelado;
	}
	
	/**
	 * Gera o ID de uma requisicao do item de um emprestimo.
	 */
	public void geraIDRequisicao() {
		this.idRequisicao = item.getID();
	}
	
	/**
	 * Recupera o ID de uma requisicao do item de um emprestimo.
	 * @return O ID de uma requisicao do item de um emprestimo.
	 */
	public int getIDRequisicao() {
		return idRequisicao;
	}
	
	/**
	 * Recupera o ID do emprestimo.
	 * @return O ID do emprestimo.
	 */
	public int getIDEmprestimo() {
		return idEmprestimo;
	}
	
	/**
	 * Guarda a data do inicio do emprestimo e muda a disponibilidade do item para nao disponivel.
	 * @throws DescricaoInvalidaException 
	 * @throws AssuntoInvalidoException 
	 * @throws TipoDeMensagemInvalido 
	 */
	public void iniciar() throws TipoDeMensagemInvalido, AssuntoInvalidoException, DescricaoInvalidaException {
		dataInicial = new GregorianCalendar();
		item.setDisponibilidade(false);
		idEmprestimo = RETORNA_ID++;
	}
	
	/**
	 * Retorna uma string contendo o andamento do emprestimo.
	 * @return O andamento do emprestimo.
	 */
	public String andamento() {
		if(canceladoAntes) {
			return "Cancelado";
		} if(!canceladoAntes && item.estaDisponivel()) {
			return "Completado";
		} return "Andamento";
	}
	
	/**
	 * Muda a disponibilidade do item para disponivel, finalizando o emprestimo.
	 * @throws DescricaoInvalidaException 
	 * @throws AssuntoInvalidoException 
	 * @throws TipoDeMensagemInvalido 
	 */
	public void finalizar() throws TipoDeMensagemInvalido, AssuntoInvalidoException, DescricaoInvalidaException {
		item.setDisponibilidade(true);
	}
	
	/**
	 * Modifica o status de termino do emprestimo.
	 * @param terminado Novo status de termino do emprestimo..
	 */
	public void setTermino(boolean terminado) {
		this.terminado = terminado;
	}
	
	/**
	 * Informa se um emprestido ja foi terminado.
	 * @return True se foi terminado, false caso contrario.
	 */
	public boolean foiTerminado() {
		return terminado;
	}
	
	/**
	 * Verifica se o dono do item requisitou sua devolucao antes do tempo previsto.
	 */
	public void verificaCancelado() {
		dataFinal = Gerenciador.data;
		GregorianCalendar inicio = dataInicial;
		inicio.add(Calendar.DAY_OF_YEAR, tempoPrevisto);
		if (dataFinal.get(Calendar.DAY_OF_YEAR) - inicio.get(Calendar.DAY_OF_YEAR) < 0) {
			canceladoAntes = true;
		} else {
			canceladoAntes = false;
		}
	}
	
}